﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using MongoDB.Driver;

namespace MongoServices
{
	/// <summary>
	/// This class will be used to initialize the configuration of MongoServices
	/// </summary>
	public static class MongoServicesConfig
	{
		private static Action<Assembly, Type, List<Type>> getTypes = (assembly, type, list) => {
			list.AddRange(assembly.GetTypes().Where(t => type.IsAssignableFrom(t)  && t.IsClass));
		};

		/// <summary>
		/// THis method will initialize the services, repositories and models for MongoServices use.  All classes implement 
		/// <see cref="IMongoServicesServiceInitializer"/>, <see cref="IMongoServicesRepositoryInitializer"/> or <see cref="IMongoServicesModelInitializer"/> 
		/// interface will be executed.
		/// </summary>
		public static void Initialize()
		{
			var assemblies = AppDomain.CurrentDomain.GetAssemblies().ToList();

			InitializeServiceConfig(assemblies);
			InitializeRepositoryConfig(assemblies);
			InitializeModelConfig(assemblies);
		}

		private static void InitializeModelConfig(List<Assembly> assemblies)
		{
			var types = new List<Type>();

			assemblies.ForEach(a => getTypes(a, typeof(IMongoServicesModelInitializer), types));

			foreach (var t in types)
			{
				((IMongoServicesModelInitializer)Activator.CreateInstance(t)).Setup();
			}
		}

		private static void InitializeRepositoryConfig(List<Assembly> assemblies)
		{
			var types = new List<Type>();

			assemblies.ForEach(a => getTypes(a, typeof(IMongoServicesRepositoryInitializer), types));

			foreach (var t in types)
			{
				((IMongoServicesRepositoryInitializer)Activator.CreateInstance(t)).Setup();
			}
		}

		private static void InitializeServiceConfig(List<Assembly> assemblies)
		{
			var types = new List<Type>();

			assemblies.ForEach(a => getTypes(a, typeof(IMongoServicesServiceInitializer), types));

			foreach (var t in types)
			{
				((IMongoServicesServiceInitializer)Activator.CreateInstance(t)).Setup();
			}
		}

		/// <summary>
		/// Sets the MongoUrl provider for the all repositories, unless there is on specified for the specific repository.
		/// </summary>
		/// <param name="provider">A <code>Func&lt;MongoUrl&gt;</code> that will return the appropriate MongoUrl.</param>
		public static void SetMongoUrlProvider(Func<MongoUrl> provider)
		{
			GlobalConfigContainer.Instance.MongoUrlProvider = provider;
		}
	}
}
